package com.zz.itext7;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.element.Image;
import com.itextpdf.signatures.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.swing.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Map;
import java.util.function.BiConsumer;

//电子签章
public class demo3 {
    /**
    * @Description: TODO
    * @Param: src  需要签章的pdf文件路径
    * @Param: dest 签完章的pdf文件路径
    * @Param: chain 证书链
    * @Param: pk  签名私钥
    * @Param: digestAlgorithm  摘要算法名称，例如SHA-1
    * @Param: provider  密钥算法提供者，可以为null
    * @Param: subfilter  数字签名格式，itext有2种
    * @Param: reason  签名的原因，显示在pdf签名属性中，随便填
    * @Param: location  签名的地点，显示在pdf签名属性中，随便填
    * @return: void
    * @Author: zhangzhen
    * @Date: 2018/10/30 10:26
    */
    public static final String KEYSTORE="D:\\zhengshu.p12";//证书位置
    public static final char[] PASSWORD="123456".toCharArray();//密码
    public static final String SRC="D:\\测试pdf\\demo2.pdf";//模板位置
    public static final String DEST="D:\\测试pdf\\day6_2.pdf";//目标位置
    public static final String stamperSrc="D:\\1540880250387.png";//签章位置
    public static PdfFont cnFont = null;
    public void sign (String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm , String provider  , PdfSigner.CryptoStandard subfilter ,String reason ,String location) throws  Exception{
        PdfReader reader = new PdfReader(src);
        //PdfDocument pdf = new PdfDocument(reader);
        //pdf.setDefaultPageSize(PageSize.TABLOID);
        //输出流
        FileOutputStream os = new FileOutputStream(dest);
        //创建电子签章工具PdfSigner,最后一个参数boolean
        //false的话，pdf文件只允许被签名一次，多次签名，最后一次有效
        //true的话，pdf文件可以被追加签名，签名工具可以识别出每次签名之后文档是否被修改
        PdfSigner signer = new PdfSigner(reader,os,true);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        appearance.setReuseAppearance(false);
        ImageData imageData = ImageDataFactory.create(stamperSrc);
        //读取图章图片，这个image是Itext包的image
        Image image = new Image(imageData);
        float height = image.getImageHeight();
        float width  = image.getImageWidth();
        //设置签名位置，页码。签名域名称，多次追加签名的时候，签名与名称不能一样
        //签名的位置，是图章相对于pdf页面的位置图标，原点为pdf页面左下角
        //四个参数分别是 图章左下角x 图章左下角y 图章宽度  图章高度
        appearance.setPageNumber(1);
        appearance.setPageRect(new Rectangle(50,100,width,height));
        //插入签章图片
        appearance.setSignatureGraphic(imageData);
        //设置图章显示方式，如下选择的是只显示图章（还有其他方式，可以图章和签名描述一起显示）
        appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
        //这里的itext提供了2个用于签名的接口，可以自己实现，
        // 摘要算法
        IExternalDigest digest = new BouncyCastleDigest();
        // 签名算法
        IExternalSignature signature = new PrivateKeySignature(pk,digestAlgorithm, provider);
        //调用itext签名方法完成pdf签章
        signer.setCertificationLevel(1);
        signer.signDetached(digest,signature,chain,null,null,null,0,subfilter);
    }

    public static void main(String[] args) {
        try {
            BouncyCastleProvider provider = new BouncyCastleProvider();
            Security.addProvider(provider);
            demo3 app = new demo3();
            //将证书文件放入指定路径，并读取keystore ，获得私钥和证书链
            //String pkPath = app.getClass().getResource("D:\\zhengshu.p12").getPath();
            // 读取keystore ，获得私钥和证书链 PKCS12
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(new FileInputStream(KEYSTORE), PASSWORD);
            String alias = (String) ks.aliases().nextElement();
            PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
            Certificate[] chain = ks.getCertificateChain(alias);


            // 调用签名方法
            app.sign(SRC, String.format(DEST, 1), chain, pk, DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent");
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, e.getMessage());
            e.printStackTrace();
        }
    }
}
